#include "EventInstr.h"
#include "MemoryInstr.h"
#include <syslog.h>
#include <unistd.h>

map<Function*, EventProfiler*> EventProfiler::ByFunc;

EventProfiler::EventProfiler(Instruction *&Inst, InstrumenterBase *Instrumenter) :
	F(Inst->getParent()->getParent()),
	SG(F, Inst, Instrumenter->EE),
	Instrumenter(Instrumenter)
{
	vector<MemoryProfiler*> &V = MemoryProfiler::ofFunc[F];
	Begin = &V[0];
	End = Begin + V.size();
	EventProfiler::ByFunc[F] = this;
}

bool EventProfiler::HasHotLoads()
{
	for (MemoryProfiler **I = Begin; I != End; ++I)
		if ((*I)->Misses > 0)
			return true;
	return false;
}

//REFACTOR!!

void EventProfiler::Profile(int) {
//	if (!HasHotLoads())
//		return;

//	vector<Instruction*> HotLoads;

	size_t OldSize = HotLoadsSet.size();
	AllHotLoads.clear();
	HotLoadsSet.clear();

	for (MemoryProfiler **I = Begin; I != End; ++I)
	{
		MemoryProfiler *Profiler = *I;
		int Misses = Profiler->Misses;
		Profiler->Misses = 0;
		//Profiler->Total = 0;
		if (Misses < 2)
			continue;
		errs() << "Hot load " << *(Profiler->Inst) << " with " << Misses
				<< " in " << Profiler->Inst->getParent()->getParent()->getNameStr() << "\n";
		if (HotLoadsSet.find(Profiler->Inst) != HotLoadsSet.end())
			continue;
		//Profiler->Disable();
		HotLoadsSet.insert(Profiler->Inst);
		AllHotLoads.push_back(Profiler->Inst);
	}

	if (!NewlyFound.empty()) {
		errs() << "ignoring all hot loads\n";
		HotLoadsSet.clear();
		AllHotLoads.clear();
	}

	for (set<Instruction*>::iterator I = NewlyFound.begin(), E = NewlyFound.end(); I != E; ++I)
	{
		errs() << "Newly found hot load " << **I << "\n";
		HotLoadsSet.insert(*I);
		AllHotLoads.push_back(*I);
	}

//	if (OldSize == HotLoadsSet.size())
//		return;

	if (!SG.SliceAndCompile(AllHotLoads))
		return;

	MemoryProfiler::Enabled = false;
	errs() << "generated slice\n";

//	vector<MySampler*> &Vec = MySampler::ofFunc[F];
//	for (vector<MySampler*>::iterator I = Vec.begin(), E = Vec.end(); I != E; ++I)
//	{
//		(*I)->Enabled = false;
//	}
}


EventInstrumenter::EventInstrumenter(Module *M, ExecutionEngine *EE) : EventBase(M, EE) { }

Value* EventInstrumenter::InstrumentThis(Instruction *Inst)
{
	return Inst == Inst->getParent()->getParent()->front().getFirstNonPHI() ? Dummy : 0;
}
